//
// Created by Langingsing on 2021/10/25.
//

#ifndef PROJ_LINEAR_H
#define PROJ_LINEAR_H
#include <sys/types.h>
#include <iostream>
#include <cstdlib>
#include <limits>
#include <stdexcept>

using namespace std;

template<typename T>
class Linear
{
protected:
    static const size_t INITIAL_CAPACITY = 255;
    size_t _capacity;
    size_t _size;
    T *_basePtr;

    /// 判满
    inline bool _full() const;

    /// 扩容
    virtual bool _expandCapacity();

public:
    Linear();

    Linear(Linear<T> const &l);

    ~Linear();

    /// 获取大小
    inline size_t size() const;

    /// 获取数组起点
    inline T *basePtr() const;

    /// 判空
    inline bool empty() const;
};

template<typename T>
Linear<T>::Linear()
        :_capacity(INITIAL_CAPACITY),
         _size(0),
         _basePtr((T *) malloc(sizeof(T) * _capacity))
{
    if (!_basePtr) {
        cout << "FAIL TO ALLOCATE MEMORY" << endl;
        throw bad_alloc();
    }
}

template<typename T>
Linear<T>::Linear(Linear<T> const &l)
        :_size(l.size()),           // 复制大小
         _capacity(l._capacity),    // 复制容量
         _basePtr((T *) malloc(sizeof(T) * _capacity)) // 分配内存
{
    if (!_basePtr) {
        cout << "FAIL TO ALLOCATE MEMORY" << endl;
        throw bad_alloc();
    }

    auto const origin = l.basePtr();
    for (size_t i = 0; i < _size; ++i)
        _basePtr[i] = origin[i];    // 深拷贝
}

template<typename T>
Linear<T>::~Linear()
{
    free(_basePtr);
}

template<typename T>
inline bool Linear<T>::_full() const
{
    return _size == _capacity;
}

template<typename T>
bool Linear<T>::_expandCapacity()
{
    const size_t umax = numeric_limits<size_t>::max();
    const ssize_t max = numeric_limits<ssize_t>::max();

    if (umax == _capacity) // 到达极限
        return false;

    const size_t
            newCapacity = _capacity > max
                          ? umax                     // 扩容至size_t的最大值
                          : (_capacity << 1u) + 1;   // 扩容至两倍再加一

    T *newBase = (T *) realloc(_basePtr, newCapacity * sizeof(T)); // 重新分配内存

    if (nullptr == newBase) // 分配失败
        return false;

    _basePtr = newBase;         // 重新赋值
    _capacity = newCapacity;    // 重设容量
    return true;
}

template<typename T>
inline size_t Linear<T>::size() const
{
    return _size;
}

template<typename T>
inline T *Linear<T>::basePtr() const
{
    return _basePtr;
}

template<typename T>
inline bool Linear<T>::empty() const
{
    return _size == 0;
}

#endif //PROJ_LINEAR_H
